

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/fluid.png">
  <link rel="icon" href="/img/fluid.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="叶飞">
  <meta name="keywords" content="">
  
    <meta name="description" content="1 简述Redis  Redis: ：Remote Dictionary Server，本质上是一个Key-Value类型的内存数据库，很像memcached，整个数据库统统加载在内存当中进行操作，定期通过异步操作把数据库数据flush到硬盘上进行保存【持久化】。 每秒可以处理超过 10万次读写操作 Redis最大的魅力是支持保存多种数据结构，此外单个value的最大限制是1GB，不像 memc">
<meta property="og:type" content="article">
<meta property="og:title" content="redis面试题-1">
<meta property="og:url" content="http://example.com/2022/04/03/redis%E9%9D%A2%E8%AF%95%E9%A2%98-1/index.html">
<meta property="og:site_name" content="博客">
<meta property="og:description" content="1 简述Redis  Redis: ：Remote Dictionary Server，本质上是一个Key-Value类型的内存数据库，很像memcached，整个数据库统统加载在内存当中进行操作，定期通过异步操作把数据库数据flush到硬盘上进行保存【持久化】。 每秒可以处理超过 10万次读写操作 Redis最大的魅力是支持保存多种数据结构，此外单个value的最大限制是1GB，不像 memc">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://example.com/img/redis-1/redis1.png">
<meta property="article:published_time" content="2022-04-03T07:19:32.000Z">
<meta property="article:modified_time" content="2022-04-03T09:37:39.010Z">
<meta property="article:author" content="叶飞">
<meta property="article:tag" content="面试">
<meta property="article:tag" content="redis">
<meta property="article:tag" content="数据库">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="http://example.com/img/redis-1/redis1.png">
  
  
  
  <title>redis面试题-1 - 博客</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.9.2","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  


  
<meta name="generator" content="Hexo 6.2.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>No Tomorrow</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/default.png') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="redis面试题-1"></span>
          
        </div>

        
          
  <div class="mt-3">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-author" aria-hidden="true"></i>
        叶飞
      </span>
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2022-04-03 15:19" pubdate>
          星期日, 四月 3日 2022, 3:19 下午
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          <!-- compatible with older versions-->
          7k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          <!-- compatible with older versions-->
          59 分钟
        
      </span>
    

    
    
      
        <span id="leancloud-page-views-container" class="post-meta" style="display: none">
          <i class="iconfont icon-eye" aria-hidden="true"></i>
          <span id="leancloud-page-views"></span> 次
        </span>
        
      
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">redis面试题-1</h1>
            
            
              <div class="markdown-body">
                
                <h2 id="1-简述redis"><a class="markdownIt-Anchor" href="#1-简述redis"></a> 1 简述Redis</h2>
<ul>
<li>Redis: ：<code>Remote Dictionary Server</code>，本质上是一个Key-Value类型的内存数据库，很像memcached，整个数据库统统加载在<code>内存</code>当中进行操作，定期通过异步操作把数据库数据flush到硬盘上进行保存【持久化】。</li>
<li>每秒可以处理超过 10万次读写操作</li>
<li>Redis最大的魅力是支持保存<code>多种数据结构</code>，此外单个value的最大限制是<code>1GB</code>，不像 memcached只能保存1MB的数据，因此Redis可以用来实现很多有用的功能。
<ul>
<li>List：FIFO双向链表–&gt; 轻量级的消息队列服务</li>
<li>Set：高性能tag系统</li>
</ul>
</li>
<li>性能受限于物理机的内存</li>
<li>适用场景：较小数据量的高性能操作和运算上</li>
</ul>
<hr>
<p>Redis本质上是一个Key-Value类型的内存数据库，很像Memcached，整个数据库加载在内存当中操作，定期通过异步操作把数据库中的数据flush到硬盘上进行保存。</p>
<p>因为是纯内存操作，Redis的性能非常出色，每秒可以处理超过 10万次读写操作，是已知性能最快的Key-Value 数据库。</p>
<p><strong>优点</strong>：</p>
<ul>
<li>读写性能极高， Redis能读的速度是110000次/s，写的速度是81000次/s。</li>
<li>支持数据持久化，支持AOF和RDB两种持久化方式。</li>
<li>支持事务， Redis的所有操作都是原子性的，意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务，即原子性，通过MULTI和EXEC指令包起来。</li>
<li>数据结构丰富，除了支持string类型的value外，还支持hash、set、zset、list等数据结构。</li>
<li>支持主从复制，主机会自动将数据同步到从机，可以进行读写分离。</li>
<li>丰富的特性 – Redis还支持 publish/subscribe， 通知， key 过期等特性。</li>
</ul>
<p><strong>缺点</strong>：</p>
<ul>
<li>数据库容量受到物理内存的限制，不能用作海量数据的高性能读写，因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。</li>
<li>主机宕机，宕机前有部分数据未能及时同步到从机，切换IP后还会引入数据不一致的问题，降低了系统的可用性。</li>
</ul>
<h2 id="2-redis的数据类型有哪些"><a class="markdownIt-Anchor" href="#2-redis的数据类型有哪些"></a> 2. Redis的数据类型有哪些？</h2>
<p>有五种常用数据类型：<code>String、Hash、Set、List、SortedSet</code>。以及三种特殊的数据类型：<code>Bitmap、HyperLogLog、Geospatial</code> ，其中HyperLogLog、Bitmap的底层都是 String 数据类型，Geospatial 的底层是 Sorted Set 数据类型。</p>
<p><strong>五种常用的数据类型</strong>：</p>
<ul>
<li>
<p>1、<code>String</code>：String是最常用的一种数据类型，普通的key- value 存储都可以归为此类。其中Value既可以是数字也可以是字符串。使用场景：常规key-value缓存应用。常规计数: 微博数， 粉丝数。</p>
</li>
<li>
<p>2、<code>Hash</code>：Hash 是一个键值(key =&gt; value)对集合。Redishash 是一个 string 类型的 field 和 value 的映射表，hash 特别适合用于存储对象，并且可以像数据库中update一个属性一样只修改某一项属性值。</p>
</li>
<li>
<p>3、<code>Set</code>：Set是一个无序的天然去重的集合，即Key-Set。此外还提供了交集、并集等一系列直接操作集合的方法，对于求共同好友、共同关注什么的功能实现特别方便。</p>
</li>
<li>
<p>4、<code>List</code>：List是一个有序可重复的集合，其遵循FIFO的原则，底层是依赖双向链表实现的，因此支持正向、反向双重查找。通过List，我们可以很方面的获得类似于最新回复这类的功能实现。</p>
</li>
<li>
<p>5、<code>SortedSet</code>：类似于java中的TreeSet，是Set的可排序版。此外还支持优先级排序，维护了一个score的参数来实现。适用于排行榜和带权重的消息队列等场景。</p>
</li>
</ul>
<p><strong>三种特殊的数据类型</strong>：</p>
<ul>
<li>
<p>1、<code>Bitmap</code>：位图，Bitmap想象成一个以位为单位数组，数组中的每个单元只能存0或者1，数组的下标在Bitmap中叫做偏移量。使用Bitmap实现统计功能，更省空间。如果只需要统计数据的二值状态，例如商品有没有、用户在不在等，就可以使用 Bitmap，因为它只用一个 bit 位就能表示 0 或 1。</p>
</li>
<li>
<p>2、<code>Hyperloglog</code>。HyperLogLog 是一种用于统计基数的数据集合类型，HyperLogLog 的优点是，在输入元素的数量或者体积非常非常大时，计算基数所需的空间总是固定 的、并且是很小的。每个 HyperLogLog 键只需要花费 12 KB 内存，就可以计算接近 2^64 个不同元素的基 数。场景：统计网页的UV（即Unique Visitor，不重复访客，一个人访问某个网站多次，但是还是只计算为一次）。</p>
<p>要注意，HyperLogLog 的统计规则是基于概率完成的，所以它给出的统计结果是有一定误差的，标准误算率是 0.81%。</p>
</li>
<li>
<p>3、<code>Geospatial</code> ：主要用于存储地理位置信息，并对存储的信息进行操作，适用场景如朋友的定位、附近的人、打车距离计算等。</p>
</li>
</ul>
<h2 id="3-redis的并发竞争问题如何解决"><a class="markdownIt-Anchor" href="#3-redis的并发竞争问题如何解决"></a> 3 Redis的并发竞争问题如何解决?</h2>
<p>单进程单线程模式，采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念，Redis对于多个客户端连接并不存在竞争，利用setnx实现锁。</p>
<h2 id="4-redis为什么这么快"><a class="markdownIt-Anchor" href="#4-redis为什么这么快"></a> 4 Redis为什么这么快？</h2>
<ul>
<li>内存存储：Redis是使用内存(in-memeroy)存储，没有磁盘IO上的开销。数据存在内存中，类似于 HashMap，HashMap 的优势就是查找和操作的时间复杂度都是O(1)。</li>
<li>单线程实现（ Redis 6.0以前）：Redis使用单个线程处理请求，避免了多个线程之间线程切换和锁资源争用的开销。注意：单线程是指的是在核心网络模型中，网络请求模块使用一个线程来处理，即一个线程处理所有网络请求。</li>
<li>非阻塞IO：Redis使用多路复用IO技术，将epoll作为I/O多路复用技术的实现，再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件，不在网络I/O上浪费过多的时间。</li>
<li>优化的数据结构：Redis有诸多可以直接应用的优化数据结构的实现，应用层可以直接使用原生的数据结构提升性能。</li>
<li>使用底层模型不同：Redis直接自己构建了 VM (虚拟内存)机制 ，因为一般的系统调用系统函数的话，会浪费一定的时间去移动和请求。</li>
</ul>
<blockquote>
<p>Redis的VM(虚拟内存)机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中，从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离，使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。</p>
<p>Redis提高数据库容量的办法有两种：一种是可以将数据分割到多个RedisServer上；另一种是使用虚拟内存把那些不经常访问的数据交换到磁盘上。<strong>需要特别注意的是Redis并没有使用OS提供的Swap，而是自己实现。</strong></p>
</blockquote>
<h2 id="5-redis相比memcached有哪些优势"><a class="markdownIt-Anchor" href="#5-redis相比memcached有哪些优势"></a> 5 Redis相比Memcached有哪些优势？</h2>
<ul>
<li>
<p><strong>数据类型</strong>：Memcached所有的值均是简单的字符串，Redis支持更为丰富的数据类型，支持string(字符串)，list(列表)，Set(集合)、Sorted Set(有序集合)、Hash(哈希)等。</p>
</li>
<li>
<p><strong>持久化</strong>：Redis支持数据落地持久化存储，可以将内存中的数据保持在磁盘中，重启的时候可以再次加载进行使用。 memcache不支持数据持久存储 。</p>
</li>
<li>
<p><strong>集群模式</strong>：Redis提供主从同步机制，以及 Cluster集群部署能力，能够提供高可用服务。Memcached没有原生的集群模式，需要依靠客户端来实现往集群中分片写入数据</p>
</li>
<li>
<p><strong>性能对比</strong>：Redis的速度比Memcached快很多。</p>
</li>
<li>
<p>网络IO模型：Redis使用<code>单线程的多路 IO 复用模型</code>，Memcached使用多线程的非阻塞IO模式。</p>
</li>
<li>
<p>Redis支持服务器端的数据操作：Redis相比Memcached来说，拥有更多的数据结构和并支持更丰富的数据操作，通常在Memcached里，你需要将数据拿到客户端来进行类似的修改再set回去。</p>
<p>这大大增加了网络IO的次数和数据体积。在Redis中，这些复杂的操作通常和一般的GET/SET一样高效。所以，如果需要缓存能够支持更复杂的结构和操作，那么Redis会是不错的选择。</p>
</li>
</ul>
<h2 id="6-为什么要用-redis-做缓存"><a class="markdownIt-Anchor" href="#6-为什么要用-redis-做缓存"></a> 6 为什么要用 Redis 做缓存？</h2>
<p><strong>从高并发上来说：</strong>(缓存的好处)</p>
<ul>
<li>直接操作缓存能够承受的请求是远远大于直接访问数据库的，所以我们可以考虑把数据库中的部分数据转移到缓存中去，这样用户的一部分请求会直接到缓存这里而不用经过数据库。</li>
</ul>
<p><strong>从高性能上来说：</strong></p>
<ul>
<li>用户第一次访问数据库中的某些数据。 因为是从硬盘上读取的所以这个过程会比较慢。将该用户访问的数据存在缓存中，下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存，所以速度相当快。如果数据库中的对应数据改变的之后，同步改变缓存中相应的数据。</li>
</ul>
<h2 id="7-为什么要用-redis-而不用-mapguava-做缓存"><a class="markdownIt-Anchor" href="#7-为什么要用-redis-而不用-mapguava-做缓存"></a> 7 为什么要用 Redis 而不用 map/guava 做缓存?</h2>
<p>缓存分为<code>本地缓存</code>和<code>分布式缓存</code>。</p>
<ul>
<li>
<p>以java为例，使用自带的map或者guava实现的是<code>本地缓存</code>，最主要的特点是轻量以及快速，生命周期随着jvm的销毁而结束，并且在多实例的情况下，每个实例都需要各自保存一份缓存，缓存不具有一致性。</p>
</li>
<li>
<p>使用Redis或memcached之类的称为<code>分布式缓存</code>，在多实例的情况下，各实例共用一份缓存数据，缓存具有一致性。缺点是需要保持Redis或memcached服务的高可用，整个程序架构上较为复杂。</p>
</li>
</ul>
<p>对比:</p>
<ul>
<li>Redis 可以用几十 G 内存来做缓存，Map 不行，一般 JVM 也就分几个 G 数据就够大了；</li>
<li>Redis 的缓存可以<code>持久化</code>，Map 是内存对象，程序一重启数据就没了；</li>
<li>Redis 可以实现<code>分布式的缓存</code>，Map 只能存在创建它的程序里；</li>
<li>Redis 可以处理<code>每秒百万级的并发</code>，是专业的缓存服务，Map 只是一个普通的对象；</li>
<li>Redis 缓存有<code>过期机制</code>，Map 本身无此功能；Redis 有丰富的 API，Map 就简单太多了；</li>
<li>Redis可单独部署，多个项目之间可以共享，本地内存无法共享；</li>
<li>Redis有专门的管理工具可以查看缓存数据。</li>
</ul>
<h1 id="持久化"><a class="markdownIt-Anchor" href="#持久化"></a> 持久化</h1>
<h2 id="8-redis持久化机制"><a class="markdownIt-Anchor" href="#8-redis持久化机制"></a> 8 Redis持久化机制？</h2>
<p>为了能够重用Redis数据，或者防止系统故障，我们需要将Redis中的数据写入到磁盘空间中，即持久化。</p>
<p>Redis提供了两种不同的持久化方法可以将数据存储在磁盘中，一种叫快照<code>RDB</code>，另一种叫只追加文件<code>AOF</code>。</p>
<ul>
<li><strong>RDB</strong></li>
</ul>
<p>在指定的时间间隔内将内存中的数据集快照写入磁盘(<code>Snapshot</code>)，它恢复时是将快照文件直接读到内存里。</p>
<p><strong>优势</strong>：适合大规模的数据恢复；对数据完整性和一致性要求不高</p>
<p><strong>劣势</strong>：在一定间隔时间做一次备份，所以如果Redis意外<code>down</code>掉的话，就会丢失最后一次快照后的所有修改。</p>
<ul>
<li><strong>AOF</strong></li>
</ul>
<p>以日志的形式来记录每个写操作，将Redis执行过的所有写指令记录下来(读操作不记录)，只许追加文件但不可以改写文件，Redis启动之初会读取该文件重新构建数据，换言之，Redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。</p>
<p>AOF采用文件追加方式，文件会越来越大，为避免出现此种情况，新增了重写机制，当AOF文件的大小超过所设定的阈值时， Redis就会启动AOF文件的内容压缩，只保留可以恢复数据的最小指令集.。</p>
<p><strong>优势</strong></p>
<ul>
<li>每修改同步：<code>appendfsync always</code> 同步持久化，每次发生数据变更会被立即记录到磁盘，性能较差但数据完整性比较好</li>
<li>每秒同步：<code>appendfsync everysec</code> 异步操作，每秒记录，如果一秒内宕机，有数据丢失</li>
<li>不同步：<code>appendfsync no</code> 从不同步</li>
</ul>
<p><strong>劣势</strong></p>
<ul>
<li>相同数据集的数据而言<code>aof</code>文件要远大于<code>rdb</code>文件，恢复速度慢于<code>rdb</code></li>
<li><code>aof</code>运行效率要慢于<code>rdb</code>，每秒同步策略效率较好，不同步效率和<code>rdb</code>相同</li>
</ul>
<h2 id="9-如何选择合适的持久化方式"><a class="markdownIt-Anchor" href="#9-如何选择合适的持久化方式"></a> 9 如何选择合适的持久化方式</h2>
<ul>
<li>如果是数据不那么敏感，且可以从其他地方重新生成补回的，那么可以关闭持久化。</li>
<li>如果是数据比较重要，不想再从其他地方获取，且可以承受数分钟的数据丢失，比如缓存等，那么可以只使用RDB。</li>
<li>如果是用做内存数据库，要使用Redis的持久化，建议是RDB和AOF都开启，或者定期执行bgsave做快照备份，RDB方式更适合做数据的备份，AOF可以保证数据的不丢失。</li>
</ul>
<p><strong>补充：Redis4.0 对于持久化机制的优化</strong></p>
<p>Redis4.0相对与3.X版本其中一个比较大的变化是4.0添加了新的混合持久化方式。</p>
<p>简单的说：新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据，如下图：</p>
<p><img src="/img/redis-1/redis1.png" srcset="/img/loading.gif" lazyload alt="img">)</p>
<p><strong>优势</strong>：混合持久化结合了RDB持久化 和 AOF 持久化的优点， 由于绝大部分都是RDB格式(快照)，加载速度快，同时结合AOF，增量的数据以AOF方式保存了，数据更少的丢失。</p>
<p><strong>劣势</strong>：兼容性差，一旦开启了混合持久化，在4.0之前版本都不识别该aof文件，同时由于前部分是RDB格式，阅读性较差。</p>
<h2 id="10-redis持久化数据和缓存怎么做扩容"><a class="markdownIt-Anchor" href="#10-redis持久化数据和缓存怎么做扩容"></a> 10. Redis持久化数据和缓存怎么做扩容？</h2>
<ul>
<li>如果Redis被当做<code>缓存</code>使用，使用<code>一致性哈希</code>实现动态扩容缩容。</li>
<li>如果Redis被当做一个<code>持久化存储</code>使用，必须使用固定的keys-to-nodes映射关系，节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况），必须使用可以在运行时进行数据再平衡的一套系统，而当前只有Redis集群可以做到这样。</li>
</ul>
<h1 id="删除和淘汰策略"><a class="markdownIt-Anchor" href="#删除和淘汰策略"></a> 删除和淘汰策略</h1>
<h2 id="11-过期键的删除策略"><a class="markdownIt-Anchor" href="#11-过期键的删除策略"></a> 11. 过期键的删除策略</h2>
<p><strong>Redis的过期删除策略就是：惰性删除和定期删除两种策略配合使用。</strong></p>
<ul>
<li>
<p><strong>惰性删除</strong>：惰性删除不会去主动删除数据，而是在访问数据的时候，再检查当前键值是否过期，如果过期则执行删除并返回 null 给客户端，如果没有过期则返回正常信息给客户端。它的优点是简单，不需要对过期的数据做额外的处理，只有在每次访问的时候才会检查键值是否过期，缺点是删除过期键不及时，造成了一定的空间浪费。</p>
</li>
<li>
<p><strong>定期删除</strong>：Redis会周期性的随机测试一批设置了过期时间的key并进行处理。测试到的已过期的key将被删除。</p>
<ul>
<li>
<p><strong>1、定时删除</strong></p>
<p>在设置某个key 的过期时间同时，我们创建一个定时器，让定时器在该过期时间到来时，立即执行对其进行删除的操作。</p>
<p><strong>优点</strong>：定时删除对内存是最友好的，能够保存内存的key一旦过期就能立即从内存中删除。</p>
<p><strong>缺点</strong>：对CPU最不友好，在过期键比较多的时候，删除过期键会占用一部分 CPU 时间，对服务器的响应时间和吞吐量造成影响。</p>
</li>
<li>
<p><strong>2、惰性删除</strong></p>
</li>
</ul>
<p>设置该key 过期时间后，我们不去管它，当需要该key时，我们在检查其是否过期，如果过期，我们就删掉它，反之返回该key。</p>
<p><strong>优点</strong>：对 CPU友好，我们只会在使用该键时才会进行过期检查，对于很多用不到的key不用浪费时间进行过期检查。</p>
<p><strong>缺点</strong>：对内存不友好，如果一个键已经过期，但是一直没有使用，那么该键就会一直存在内存中，如果数据库中有很多这种使用不到的过期键，这些键便永远不会被删除，内存永远不会释放。从而造成内存泄漏。</p>
<ul>
<li><strong>3、定期删除</strong></li>
</ul>
<p>每隔一段时间，我们就对一些key进行检查，删除里面过期的key。</p>
<p><strong>优点</strong>：可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除，也能有效释放过期键占用的内存。</p>
<p><strong>缺点</strong>：难以确定删除操作执行的时长和频率。如果执行的太频繁，定期删除策略变得和定时删除策略一样，对CPU不友好。如果执行的太少，那又和惰性删除一样了，过期键占用的内存不会及时得到释放。另外最重要的是，在获取某个键时，如果某个键的过期时间已经到了，但是还没执行定期删除，那么就会返回这个键的值，这是业务不能忍受的错误。</p>
</li>
</ul>
<h2 id="12-redis-key的过期时间和永久有效分别怎么设置"><a class="markdownIt-Anchor" href="#12-redis-key的过期时间和永久有效分别怎么设置"></a> 12. Redis key的过期时间和永久有效分别怎么设置？</h2>
<p>通过<code>expire</code>或<code>pexpire</code>命令，客户端可以以<code>秒</code>或<code>毫秒</code>的精度为数据库中的某个键设置生存时间。</p>
<p>与<code>expire</code>和p<code>expire</code>命令类似，客户端可以通过expireat和pexpireat命令，以秒或毫秒精度给数据库中的某个键设置过期时间，可以理解为：让某个键在某个时间点过期。</p>
<h2 id="13-redis的淘汰策略"><a class="markdownIt-Anchor" href="#13-redis的淘汰策略"></a> 13 Redis的淘汰策略</h2>
<h3 id="redisv40前提供-6种数据淘汰策略"><a class="markdownIt-Anchor" href="#redisv40前提供-6种数据淘汰策略"></a> <strong>Redisv4.0前提供 6种数据淘汰策略</strong>：</h3>
<ul>
<li>noeviction</li>
</ul>
<p>不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。大多数写命令都会导致占用更多的内存(有极少数会例外。</p>
<ul>
<li><code>allkeys-lru</code></li>
</ul>
<p>所有key通用; 优先删除<code>最近最少使用(less recently used ,LRU)</code> 的 key。</p>
<ul>
<li><code>volatile-lru</code></li>
</ul>
<p>只限于设置了 expire 的部分【过期集合的键】; 优先删除<code>最近最少使用(less recently used ,LRU)</code>的 key。</p>
<ul>
<li><code>allkeys-random</code></li>
</ul>
<p>所有key通用; 随机删除一部分 key。</p>
<ul>
<li>volatile-random:</li>
</ul>
<p>只限于设置了 expire 的部分; 随机删除一部分 key。</p>
<ul>
<li>volatile-ttl</li>
</ul>
<p>只限于设置了 expire 的部分; 优先删除<code>剩余时间(time to live,TTL) 短</code>的key。</p>
<h3 id="redisv40后增加以下两种"><a class="markdownIt-Anchor" href="#redisv40后增加以下两种"></a> <strong>Redisv4.0后增加以下两种</strong>：</h3>
<ul>
<li><code>volatile-lfu</code>：从已设置过期时间的数据集(server.db[i].expires)中挑选<code>最不经常使用的数据淘汰(LFU(Least Frequently Used)</code>算法，也就是最频繁被访问的数据将来最有可能被访问到)</li>
<li><code>allkeys-lfu</code>：当内存不足以容纳新写入数据时，在键空间中，移除<code>最不经常使</code>用的key。</li>
</ul>
<p>内存淘汰策略可以通过配置文件来修改，Redis.conf对应的配置项是maxmemory-policy 修改对应的值就行，默认是noeviction。</p>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/" class="category-chain-item">数据库</a>
  
  
    <span>></span>
    
  <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/" class="category-chain-item">redis</a>
  
  

  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/%E9%9D%A2%E8%AF%95/">#面试</a>
      
        <a href="/tags/redis/">#redis</a>
      
        <a href="/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/">#数据库</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>redis面试题-1</div>
      <div>http://example.com/2022/04/03/redis面试题-1/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>叶飞</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2022年4月3日</div>
        </div>
      
      
      <div class="license-meta-item">
        <div>许可协议</div>
        <div>
          
            
            
              <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
              <span class="hint--top hint--rounded" aria-label="BY - 署名">
                <i class="iconfont icon-by"></i>
              </span>
              </a>
            
          
        </div>
      </div>
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/04/03/redis%E9%9D%A2%E8%AF%95%E9%A2%98-2/" title="redis面试题-2">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">redis面试题-2</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/04/02/TCP%E9%87%8D%E4%BC%A0-%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%EF%BC%9A%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6-%E6%8B%A5%E5%A1%9E%E6%8E%A7%E5%88%B6/" title="TCP重传-滑动窗口：流量控制-拥塞控制">
                        <span class="hidden-mobile">TCP重传-滑动窗口：流量控制-拥塞控制</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  


  
  









    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
    </div>
  
  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      headingSelector : CONFIG.toc.headingSelector || 'h1,h2,h3,h4,h5,h6',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      collapseDepth   : CONFIG.toc.collapseDepth || 0,
      scrollSmooth    : true,
      headingsOffset  : -boardTop
    });
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.10/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  
      <script>
        if (!window.MathJax) {
          window.MathJax = {
            tex    : {
              inlineMath: { '[+]': [['$', '$']] }
            },
            loader : {
              load: ['ui/lazy']
            },
            options: {
              renderActions: {
                insertedScript: [200, () => {
                  document.querySelectorAll('mjx-container').forEach(node => {
                    let target = node.parentNode;
                    if (target.nodeName.toLowerCase() === 'li') {
                      target.parentNode.classList.add('has-jax');
                    }
                  });
                }, '', false]
              }
            }
          };
        } else {
          MathJax.startup.document.state(0);
          MathJax.texReset();
          MathJax.typeset();
          MathJax.typesetPromise();
        }
      </script>
    

  <script  src="https://lib.baomitu.com/mathjax/3.2.1/es5/tex-mml-chtml.js" ></script>

  <script  src="/js/local-search.js" ></script>

  <script defer src="/js/leancloud.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>
